package org.elanfox.intellicommunity.biz.service.core.msg.impl;

import lombok.extern.slf4j.Slf4j;
import org.elanfox.intellicommunity.biz.dto.condition.MsgSearchCondition;
import org.elanfox.intellicommunity.biz.dto.msg.AlarmMsgDTO;
import org.elanfox.intellicommunity.biz.dto.msg.MsgSaveDTO;
import org.elanfox.intellicommunity.biz.entity.equipment.CardPO;
import org.elanfox.intellicommunity.biz.entity.msg.AlarmMsgGroupPO;
import org.elanfox.intellicommunity.biz.entity.msg.AlarmMsgPO;
import org.elanfox.intellicommunity.biz.repository.msg.AlarmMsgRepository;
import org.elanfox.intellicommunity.biz.service.core.msg.AlarmMsgGroupService;
import org.elanfox.intellicommunity.biz.service.core.msg.AlarmMsgService;
import org.elanfox.intellicommunity.common.constant.RedisConstant;
import org.elanfox.intellicommunity.common.ienum.MsgEnums;
import org.elanfox.intellicommunity.common.utils.Jsr310Utils;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author allan
 * @version 1.0.0
 * @date 2019/12/20
 */
@Service
@Slf4j
public class AlarmMsgServiceImpl extends AbstractMsgService<AlarmMsgPO, Long> implements AlarmMsgService {
    private AlarmMsgRepository alarmMsgRepository;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private AlarmMsgGroupService alarmMsgGroupService;

    @Autowired
    protected AlarmMsgServiceImpl(AlarmMsgRepository repository) {
        super(repository);
        this.alarmMsgRepository = repository;
    }

    @Override
    protected SpecificationAndSort<AlarmMsgPO> specificationAndSort(BaseSearchDTO searchDTO) {
        MsgSearchCondition condition = (MsgSearchCondition) searchDTO;
        Specification<AlarmMsgPO> specification = (root, cq, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(normalPredicates(condition, root, cb));

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public AlarmMsgPO save(BaseSaveDTO saveDTO) {
        MsgSaveDTO msgSaveDTO = (MsgSaveDTO) saveDTO;
        CardPO cardPO = cardService.find(msgSaveDTO.getCardId());

        AlarmMsgDTO lastMsg = findLastByUser(cardPO.getUser().getUserId());

        AlarmMsgPO alarmMsgPO = new AlarmMsgPO();
        setMsgField(alarmMsgPO, msgSaveDTO, cardPO);

        if (lastMsg != null) {
            LocalDateTime begin = Jsr310Utils.DateTime.of(lastMsg.getCreateTime());
            long duration = Jsr310Utils.DateTime.duration(begin, LocalDateTime.now(), TimeUnit.SECONDS);
            //5秒记录一次
            if (duration < 5 && lastMsg.getLocatorId().equals(alarmMsgPO.getLocatorId())) {
                log.info(alarmMsgPO.getLocatorId() + "已被过滤");
                //过滤掉
                return null;
            }
        }
//        log.info("lastMsg==>" + lastMsg == null ? "null" : JSON.toJSONString(lastMsg));
        if (lastMsg == null || !lastMsg.isGroup()) {
            log.info("新建分组===>" + alarmMsgPO.getLocatorId());
            //新建分组
            AlarmMsgGroupPO alarmMsgGroupPO = new AlarmMsgGroupPO();
            alarmMsgGroupPO.setAlarmStatus(MsgEnums.AlarmStatus.ALARMING);
            alarmMsgGroupPO.setUserId(cardPO.getUser().getUserId());
            alarmMsgGroupPO.setUserName(cardPO.getUser().getName());
            alarmMsgGroupPO.setAlarmType(msgSaveDTO.getAlarmType());
            // TODO: 2020/1/8 手机号
            alarmMsgGroupPO.setUserType(cardPO.getUser().getUserType());
            alarmMsgGroupPO = alarmMsgGroupService.save(alarmMsgGroupPO);
            log.info("新建分组成功，分组id：" + alarmMsgGroupPO.getGroupId());
            alarmMsgPO.setAlarmMsgGroupPO(alarmMsgGroupPO);
            alarmMsgPO = repository.save(alarmMsgPO);
        } else {
            //同一个分组
            AlarmMsgGroupPO alarmMsgGroupPO = alarmMsgGroupService.findById(lastMsg.getGroupId());
            log.info(alarmMsgPO.getLocatorId() + "加入分组：" + alarmMsgGroupPO.getGroupId());
            alarmMsgGroupPO.setUpdateTime(LocalDateTime.now());
            alarmMsgGroupService.save(alarmMsgGroupPO);

            alarmMsgPO.setAlarmMsgGroupPO(alarmMsgGroupPO);
            alarmMsgPO = repository.save(alarmMsgPO);
        }

        AlarmMsgDTO alarmMsgDTO = new AlarmMsgDTO(alarmMsgPO);

        //覆盖redis报警信息
        redisTemplate.opsForHash().put(RedisConstant.KEY_LAST_ALARM_MSG, "user_" + alarmMsgPO.getUserId(), alarmMsgDTO);

        return alarmMsgPO;
    }

    @Override
    public AlarmMsgDTO findLastByUser(Integer userId) {
        //先去缓存
        AlarmMsgDTO alarmMsgDTO = (AlarmMsgDTO) redisTemplate.opsForHash().get(RedisConstant.KEY_LAST_ALARM_MSG, "user_" + userId);
        if (alarmMsgDTO == null) {
            AlarmMsgPO alarmMsgPO = alarmMsgRepository.findTopByUserIdOrderByCreateTimeDesc(userId);
            if (alarmMsgPO == null) {
                return null;
            }
            alarmMsgDTO = new AlarmMsgDTO(alarmMsgPO);
        }

        return alarmMsgDTO;
    }

    @Override
    public Page<AlarmMsgPO> findByGroup(Long group, int pageIndex, int pageSize) {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        Pageable pageable = PageRequest.of(pageIndex - 1, pageSize, sort);

        return alarmMsgRepository.findByAlarmMsgGroupPO_GroupId(group, pageable);
    }
}
